package com.iking.toolkit.util;

import cn.hutool.json.JSONUtil;
import com.iking.toolkit.model.Msg;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import jodd.io.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.mock.web.MockMultipartFile;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import java.nio.file.Paths;
import java.nio.charset.Charset;
import com.ibm.icu.text.CharsetDetector;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.BaseFont;
/**
 * @Description:
 * @Author: yaosong
 * @CreateTime: 2024-01-09 16:12
 **/
@Component
@Slf4j
public class TextFileUtil {

    /**
     * 下载路径
     */
    @Value("${download.file.path}")
    private String filePath;
    /**
     * 将TXT格式的MultipartFile转换为DOCX格式的MultipartFile
     * @param txtFile 上传的TXT文件
     * @return 转换后的DOCX文件（MultipartFile）
     */
    public Msg<MultipartFile> txtToDocx(MultipartFile txtFile) {
        // 基础校验
        if (txtFile.isEmpty()) {
            return Msg.fail("上传的TXT文件为空，请重新上传");
        }

        String originalFilename = txtFile.getOriginalFilename();
        if (originalFilename == null || !originalFilename.toLowerCase().endsWith(".txt")) {
            return Msg.fail("请上传扩展名为.txt的文本文件");
        }

        // 关键：同步阶段读取文件内容到内存，脱离Tomcat临时文件依赖
        byte[] txtBytes;
        try {
            txtBytes = txtFile.getBytes(); // 直接读取文件内容到字节数组
        } catch (IOException e) {
            log.error("读取TXT文件内容失败", e);
            return Msg.fail("读取文件失败：" + e.getMessage());
        }

        // 临时文件处理（自动清理）
        try (TempFileHolder tempFileHolder = new TempFileHolder()) {
            // 1. 从内存字节数组读取TXT内容（解决乱码）
            String txtContent = readTxtWithAutoEncoding(new ByteArrayInputStream(txtBytes));

            // 2. 验证模板文件是否存在
            String templateName = "template/export/txt转docx.docx";
            ClassPathResource resource = new ClassPathResource(templateName);
            if (!resource.exists()) {
                String errorMsg = "未找到转换模板：" + templateName;
                log.error(errorMsg);
                return Msg.fail(errorMsg);
            }

            // 3. 创建临时DOCX文件
            File tempDocxFile = tempFileHolder.createTempFile("converted-", ".docx");

            // 4. 填充模板生成DOCX文件（指定中文字体）
            Map<String, Object> fillMap = new HashMap<>(1);
            fillMap.put("content", txtContent);

            try (InputStream templateStream = resource.getInputStream();
                 OutputStream outputStream = Files.newOutputStream(tempDocxFile.toPath())) {
                AsposeUtil.fillData4WordTemplate(templateStream, outputStream, fillMap);
            }

            // 5. 验证生成的DOCX文件有效性
            if (tempDocxFile.length() == 0) {
                return Msg.fail("DOCX文件生成失败，文件内容为空");
            }

            // 6. 将临时文件转换为MultipartFile
            byte[] docxBytes = Files.readAllBytes(tempDocxFile.toPath());
            String docxFileName = originalFilename.replace(".txt", ".docx");

            MultipartFile resultFile = new MockMultipartFile(
                    "file",
                    docxFileName,
                    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                    docxBytes
            );

            log.info("TXT转DOCX成功，原文件名：{}，转换后文件名：{}，大小：{} bytes",
                    originalFilename, docxFileName, resultFile.getSize());

            return Msg.sucess(resultFile);

        } catch (Exception e) {
            String errorMsg = "TXT转DOCX失败：" + e.getMessage();
            log.error(errorMsg, e);
            return Msg.fail(errorMsg);
        }
    }

    /**
     * 自动检测TXT文件编码并读取内容（解决编码不匹配导致的乱码）
     */
    private String readTxtWithAutoEncoding(InputStream inputStream) throws IOException {
        // 读取文件字节用于编码检测
        byte[] fileBytes = inputStream.readAllBytes();

        // 使用ICU4J的编码检测器（支持GBK、UTF-8、ANSI等常见编码）
        CharsetDetector detector = new CharsetDetector();
        detector.setText(fileBytes);
        Charset detectedCharset = StandardCharsets.UTF_8; // 默认UTF-8

        // 获取最可能的编码
        if (detector.detect() != null) {
            String charsetName = detector.detect().getName();
            try {
                detectedCharset = Charset.forName(charsetName);
                log.info("检测到TXT文件编码：{}", charsetName);
            } catch (Exception e) {
                log.warn("不支持的编码格式：{}，将使用默认UTF-8", charsetName);
            }
        }

        // 用检测到的编码读取文本内容
        return new String(fileBytes, detectedCharset);
    }
    /**
     * 将MultipartFile（TXT）转换为PDF格式的MultipartFile
     * @param txtFile 上传的TXT文件
     * @return 转换后的PDF文件（MultipartFile）
     */
    public Msg<MultipartFile> txtToPdf(MultipartFile txtFile) {
        // 基础校验
        if (txtFile.isEmpty()) {
            return Msg.fail("上传的TXT文件为空，请重新上传");
        }

        String originalFilename = txtFile.getOriginalFilename();
        if (originalFilename == null || !originalFilename.toLowerCase().endsWith(".txt")) {
            return Msg.fail("请上传扩展名为.txt的文本文件");
        }

        // 关键：同步阶段读取文件内容到内存，脱离Tomcat临时文件
        byte[] txtBytes;
        try {
            txtBytes = txtFile.getBytes(); // 直接读取文件内容到字节数组
        } catch (IOException e) {
            log.error("读取TXT文件内容失败", e);
            return Msg.fail("读取文件失败：" + e.getMessage());
        }

        // 临时文件处理
        File tempPdfFile = null;
        try {
            // 1. 从内存字节数组读取TXT内容（解决乱码）
            String content = readTxtWithAutoEncoding(new ByteArrayInputStream(txtBytes));
            log.info("读取到的TXT内容：{}", content);
            if (content.isEmpty()) {
                return Msg.fail("TXT文件内容为空，无法转换");
            }

            // 2. 创建临时PDF文件
            tempPdfFile = File.createTempFile("txt2pdf-", ".pdf");
            tempPdfFile.deleteOnExit();

            // 3. 生成PDF（保留原文本格式，支持中文）
            Document document = new Document();
            PdfWriter.getInstance(document, new FileOutputStream(tempPdfFile));
            document.open();

            // 配置中文字体
            BaseFont baseFont = BaseFont.createFont(
                    "STSong-Light",
                    "UniGB-UCS2-H",
                    BaseFont.NOT_EMBEDDED
            );
            Font chineseFont = new Font(baseFont, 12, Font.NORMAL);

            // 4. 按原文本格式填充内容
            BufferedReader reader = new BufferedReader(new StringReader(content));
            String line;
            while ((line = reader.readLine()) != null) {
                Paragraph paragraph = new Paragraph(line, chineseFont);
                paragraph.setSpacingAfter(5f);
                paragraph.setAlignment(Element.ALIGN_LEFT);
                document.add(paragraph);
            }

            document.close();

            // 5. 验证PDF文件
            if (tempPdfFile.length() == 0) {
                return Msg.fail("PDF文件生成失败，内容为空");
            }

            // 6. 转换为MultipartFile
            byte[] pdfBytes = Files.readAllBytes(tempPdfFile.toPath());
            String pdfFileName = originalFilename.replace(".txt", ".pdf");

            MultipartFile resultFile = new MockMultipartFile(
                    "file",
                    pdfFileName,
                    "application/pdf",
                    pdfBytes
            );

            log.info("TXT转PDF成功，原文件名：{}，转换后大小：{} bytes",
                    originalFilename, resultFile.getSize());
            return Msg.sucess(resultFile);

        } catch (DocumentException e) {
            String errorMsg = "PDF文档处理失败：" + e.getMessage();
            log.error(errorMsg, e);
            return Msg.fail(errorMsg);
        } catch (Exception e) {
            String errorMsg = "TXT转PDF失败：" + e.getMessage();
            log.error(errorMsg, e);
            return Msg.fail(errorMsg);
        } finally {
            if (tempPdfFile != null && tempPdfFile.exists() && !tempPdfFile.delete()) {
                log.warn("临时PDF文件清理失败：{}", tempPdfFile.getAbsolutePath());
            }
        }
    }

    /**
     * 临时文件持有者，用于自动管理临时文件生命周期
     */
    private static class TempFileHolder implements AutoCloseable {
        private File tempFile;

        public File createTempFile(String prefix, String suffix) throws IOException {
            tempFile = File.createTempFile(prefix, suffix);
            tempFile.deleteOnExit();
            return tempFile;
        }

        @Override
        public void close() {
            if (tempFile != null && tempFile.exists()) {
                boolean deleted = tempFile.delete();
                if (!deleted) {
                    log.warn("临时文件清理失败：{}", tempFile.getAbsolutePath());
                } else {
                    log.debug("临时文件已清理：{}", tempFile.getAbsolutePath());
                }
            }
        }
    }
    /**
     * @param
     * @return
     * @author yaosong
     * @description TXT转DOCX
     * @date 2024/1/9 17:06
     */
    public Msg<File> txtToDocx(InputStream in, String docxFilePath) {
        try {
            //获取对应模板
            String templateName;
            templateName = "template/export/txt转docx.docx";
            ClassPathResource resource = new ClassPathResource(templateName);
            if (!resource.exists()) {
                log.error("TXT转DOCX异常==>未获取到模板信息, docxFilePath={}, templateName={}",
                        JSONUtil.toJsonStr(docxFilePath), templateName);
            }
            //组装
            Map<String, Object> fillMap = new HashMap<>();
            Msg<File> fileMsg = convert(in, filePath + SysUtil.getUUID() + ".txt");
            if (!fileMsg.isSuccess()) {
                log.error("流转文件异常，原因：", fileMsg.getMsg());
                return Msg.fail("流转文件失败，原因：{}", fileMsg.getMsg());
            }
            fillMap.put("content", FileUtil.readString(fileMsg.getObj()));
            OutputStream outputStream = Files.newOutputStream(Paths.get(docxFilePath));
            AsposeUtil.fillData4WordTemplate(resource.getInputStream(), outputStream, fillMap);
            return Msg.sucess(new File(docxFilePath));
        } catch (Exception e) {
            log.error(e.getMessage());
            return Msg.fail("TXT转DOCX失败,原因：" + e.getMessage());
        }
    }

    /**
     * @param
     * @return
     * @author yaosong
     * @description TXT转PDF
     * @date 2024/1/9 17:06
     */
    public Msg<File> txtToPdf(InputStream in, String pdfFilePath) {
        try {
            Document document = new Document();
            document.open();
            PdfPTable table = new PdfPTable(1); // 创建一个表格，每行一个单元格
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            String line;
            while ((line = reader.readLine()) != null) {
                table.addCell(new PdfPCell(new Phrase(line))); // 将每一行内容添加到表格中
            }
            document.add(table); // 将表格添加到PDF文档中
            PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(pdfFilePath));
            File file = new File(pdfFilePath);
            document.close();
            return Msg.sucess(file);

        } catch (Exception e) {
            log.error(e.getMessage());
            return Msg.fail("TXT转DOC失败,原因：" + e.getMessage());
        }

    }


    /**
     * @param
     * @return
     * @author yaosong
     * @description PDF转TXT
     * @date 2024/1/9 17:06
     */
    public Msg<File> pdfToTxt(String pdfPath, String txtPath) {
        try {

            File file = new File(pdfPath);
            PDDocument document = PDDocument.load(file);

            // 实例化PDFTextStripper类
            PDFTextStripper pdfStripper = new PDFTextStripper();

            // 从PDF文档中检索文本
            String text = pdfStripper.getText(document);
            File textFile = new File(txtPath); // 指定输出文件名及路径
            FileWriter writer = new FileWriter(textFile);
            writer.write(text); // 将文本内容写入文件
            File fileReturn = new File(txtPath);

            writer.close(); // 关
            // 关闭文档
            document.close();

            log.info("PDF转TXT完成,req:{}", pdfPath);
            return Msg.sucess(fileReturn);
        } catch (Exception e) {
            log.error("PDF转TXT失败,原因：", e);
            return Msg.fail("PDF转TXT失败,原因：" + e.getMessage());
        }
    }


    /**
     * @param
     * @return
     * @author yaosong
     * @description 流转文件
     * @date 2024/3/7 17:56
     */
    public static Msg<File> convert(InputStream inputStream, String filePath) {
        try {
            File file = new File(filePath);
            FileOutputStream outputStream = new FileOutputStream(file);

            int bytesRead;
            byte[] buffer = new byte[1024];

            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }

            outputStream.close();
            inputStream.close();

            return Msg.sucess(file);
        } catch (IOException e) {
            log.error("流转文件异常，原因：", e);
            return Msg.fail("流转文件失败，原因：{}", e.getMessage());
        }
    }
}
